package com.triple.triplerpc.fault.retry;

import com.github.rholder.retry.*;
import com.triple.triplerpc.model.RpcResponse;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * 指数退避策略实现类 - 重试策略
 */
@Slf4j
public class ExponentialBackoffRetryStrategy implements RetryStrategy {

    /**
     * 重试机制封装方法
     * 本方法采用指数退避策略进行重试，以处理可能发生的异常
     *
     * @param callable RPC调用的逻辑封装，返回RpcResponse对象
     * @return RpcResponse 对象，包含RPC调用的结果
     * @throws Exception 如果调用过程中发生异常，并且重试次数达到最大值后仍未成功，则抛出异常
     */
    @Override
    public RpcResponse doRetry(Callable<RpcResponse> callable) throws Exception {
        System.out.println(" >>> 当前采用的重试机制 - 指数退避");
        // 构建一个Retryer实例, 用于执行可能需要重试的任务
        Retryer<RpcResponse> retryer = RetryerBuilder.<RpcResponse>newBuilder()
                .retryIfExceptionOfType(Exception.class) // 指定当发生Exception类型异常时进行重试
                // 策略为指数退避, 初始等待时间为1秒, 最大等待时间为10秒
                .withWaitStrategy(WaitStrategies.exponentialWait(1L, 10L, TimeUnit.SECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 重试五次后放弃
                .withRetryListener(new RetryListener() { // 每次重试时, 除了再次执行任务外, 打印当前的重试次数
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("重试次数 {}", attempt.getAttemptNumber());
                    }
                })
                .build();
        // 使用Retryer执行给定的Callable任务
        return retryer.call(callable);
    }

}
